package com.example.exporttemplate.utils;

import com.example.exporttemplate.domain.TableContent;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.util.Units;
import org.apache.poi.wp.usermodel.HeaderFooterType;
import org.apache.poi.xddf.usermodel.chart.*;
import org.apache.poi.xwpf.usermodel.*;
import org.openxmlformats.schemas.drawingml.x2006.chart.CTDLbls;
import org.openxmlformats.schemas.drawingml.x2006.chart.STDispBlanksAs;
import org.openxmlformats.schemas.drawingml.x2006.main.STSchemeColorVal;
import org.openxmlformats.schemas.wordprocessingml.x2006.main.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.bind.annotation.adapters.HexBinaryAdapter;
import java.io.FileInputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
import java.util.UUID;

/**
 * word工具类
 *
 * @author liulindong
 * @version 2022/7/3 23:28
 */
public class WordUtil extends XWPFDocument {
    private static XWPFDocument document = null;
    private static XWPFParagraph paragraph = null;
    private static final long LEFT_MARGIN = 800L;
    private static final long RIGHT_MARGIN = 800L;
    private static final long TOP_MARGIN = 440L;
    private static final long BOTTOM_MARGIN = 440L;

    /**
     *  初始化创建Word文件
     */
    public WordUtil(){
        document = new XWPFDocument();
    }


    /**
     * 创建一个段落
     *
     * @param position 段落位置
     *                 0：居左
     *                 1：居中
     *                 2：居右
     */
    public XWPFParagraph createParagraph(XWPFDocument document, ParagraphAlignment position){
        XWPFParagraph paragraph = document.createParagraph();
        paragraph.setAlignment(position);
        return paragraph;
    }

    /**
     *  单线边框
     */
    public void createBorder(){

        paragraph.setBorderTop(Borders.THICK);//设置上边框
        paragraph.setBorderBottom(Borders.THICK);//设置下边框
        paragraph.setBorderLeft(Borders.THICK);//设置左边框
        paragraph.setBorderRight(Borders.THICK);//设置右边框
    }

    /**
     *  双线边框
     */
    public void createBorderDouble(){
        paragraph.setBorderTop(Borders.DOUBLE);//设置上边框
        paragraph.setBorderBottom(Borders.DOUBLE);//设置下边框
        paragraph.setBorderLeft(Borders.DOUBLE);//设置左边框
        paragraph.setBorderRight(Borders.DOUBLE);//设置右边框
    }


    /**
     * 设置页边距
     * @param doc 文档
     */
    public static void setPageDistance(XWPFDocument doc) {
        CTSectPr sectPr = doc.getDocument().getBody().addNewSectPr();
        CTPageMar pageMar = sectPr.addNewPgMar();
        pageMar.setRight(BigInteger.valueOf(RIGHT_MARGIN));
        pageMar.setTop(BigInteger.valueOf(TOP_MARGIN));
        pageMar.setBottom(BigInteger.valueOf(BOTTOM_MARGIN));
        pageMar.setLeft(BigInteger.valueOf(LEFT_MARGIN));
    }

    /**
     * 首行缩进
     * @param indentation 缩进大小
     */
    public void addTextIndent(Integer indentation){
        paragraph.setIndentationFirstLine(indentation);
    }



//    /**
//     *  创建文本信息
//     * @param text 文本信息
//     * @param bold 是否加粗 true为加粗
//     * @param italic 是否倾斜 true为倾斜
//     * @param color 颜色码
//     * @param fontSize 字体大小
//     * @param fontFamily 设置字体
//     */
//    public  void createRun5_0_0(String text, Boolean bold,Boolean italic, String color,Integer fontSize,String fontFamily){
//        //创建段落文本
//        XWPFRun r = paragraph.createRun();
//        r.setText(text);
//        //设置为粗体 true 为粗体
//        r.setBold(bold);
//        //设置为倾斜 true 为粗体
//        r.setItalic(italic);
//        //设置颜色
//        r.setColor(color);
//        // 段落字体大小
//        r.setFontSize(fontSize);
//        CTRPr rpr = r.getCTR().isSetRPr() ? r.getCTR().getRPr() : r.getCTR().addNewRPr();
//        CTFonts fonts = rpr.sizeOfRFontsArray() > 0 ? rpr.getRFontsArray(0) : rpr.addNewRFonts();
//        fonts.setAscii(fontFamily);
//        fonts.setEastAsia(fontFamily);
//        fonts.setHAnsi(fontFamily);
//    }



//    /**
//     *  创建文本信息
//     * @param text 文本信息
//     * @param bold 是否加粗 true为加粗
//     * @param italic 是否倾斜 true为倾斜
//     * @param color 颜色码
//     * @param fontSize 字体大小
//     * @param fontFamily 设置字体
//     */
//    public  void createRun4_1_2(String text, Boolean bold,Boolean italic, String color,Integer fontSize,String fontFamily){
//        //创建段落文本
//        XWPFRun r = paragraph.createRun();
//        r.setText(text);
//        //设置为粗体 true 为粗体
//        r.setBold(bold);
//        //设置为倾斜 true 为粗体
//        r.setItalic(italic);
//        //设置颜色
//        r.setColor(color);
//        // 段落字体大小
//        r.setFontSize(fontSize);
//        CTRPr rpr = r.getCTR().isSetRPr() ? r.getCTR().getRPr() : r.getCTR().addNewRPr();
//        CTFonts fonts = rpr.isSetRFonts() ? rpr.getRFonts() : rpr.addNewRFonts();
//        fonts.setAscii(fontFamily);
//        fonts.setEastAsia(fontFamily);
//        fonts.setHAnsi(fontFamily);
//    }


    /**
     * 创建空行
     *
     * @param counts 空行个数
     */
    public void createEmpty(Integer counts) {
        for (int i = 0; i < counts; i++) {
            XWPFParagraph empty = document.createParagraph();
            XWPFRun e = empty.createRun();
            e.setText("");
        }
    }


    /**
     * 创建总标题
     *
     * @param doc   word文档
     * @param title 标题内容
     */
    public static void createGeneralTitle(XWPFDocument doc, String title) {
        XWPFParagraph titleParagraph = doc.createParagraph();
        //设置段落居中
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun titleParagraphRun = titleParagraph.createRun();
        titleParagraphRun.setText(title);
        titleParagraphRun.setFontFamily("宋体");
        titleParagraphRun.setColor("000000");
        titleParagraphRun.setFontSize(14);
        titleParagraphRun.setBold(true);
    }



    /**
     * 创建段落标题
     * @param doc word文档
     * @param title 标题内容
     */
    public static void createParagraphTitle(XWPFDocument doc, String title) {
        XWPFParagraph titleParagraph = doc.createParagraph();
        //设置段落居中
        titleParagraph.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun titleParagraphRun = titleParagraph.createRun();
        titleParagraphRun.setText(title);
        titleParagraphRun.setColor("000000");
//        titleParagraphRun.setFontSize(10);
        titleParagraphRun.setFontFamily("宋体");
        titleParagraphRun.setBold(true);
    }


    /**
     * 课程评价报告的第一部分
     * @param titleParagraph 第一部分段落
     * @param courseName 课程名称
     * @param requirementNames 指标点名称集合
     * @param checkNameList 考核环节名称集合
     */
    public static void partOne(XWPFParagraph titleParagraph, String courseName, List<String> requirementNames, List<String> checkNameList) {
        List<XWPFRun> runs = new ArrayList<>();

        XWPFRun courseNameRun = titleParagraph.createRun();
        // 课程名称
        courseNameRun.setText(courseName == null ? "--" : courseName);
        titleParagraph.createRun().setText("课程支撑");
        // 指标点集合
        XWPFRun requirementRun = titleParagraph.createRun();
        requirementRun.setText(CollectionUtils.isEmpty(requirementNames) ? "--" : String.join("，", requirementNames));
        // 指标点数量
        XWPFRun requirementCountRun = titleParagraph.createRun();
        requirementCountRun.setText(CollectionUtils.isEmpty(requirementNames) ? "--" : String.valueOf(requirementNames.size()));
        // 指标点
        titleParagraph.createRun().setText("个毕业要求指标点，课程目标达成度评价方法由课程组确定，考核环节由");
        // 考核列表Run
        XWPFRun checkNameRun = titleParagraph.createRun();
        checkNameRun.setText(CollectionUtils.isEmpty(checkNameList) ? "--" : String.join("、", checkNameList));
        titleParagraph.createRun().setText("组成。");
        runs.add(courseNameRun);
        runs.add(requirementRun);
        runs.add(checkNameRun);
        runs.forEach(run -> {
            // 字体颜色
            run.setColor("FF0000");
            // 下划线样式
            run.setUnderline(UnderlinePatterns.SINGLE);
            // 下划线颜色
            run.setUnderlineColor("FF0000");
        });
        titleParagraph.getRuns().forEach(run -> run.setFontFamily("宋体"));
    }


    /**
     * 课程评价报告第一部分，第一个表格，
     * @param document word文档
     */
    public static void partOneTableOne(XWPFDocument document, List<String> tableHeader) {
        // 准备数据
        List<TableContent> readyDatas = readyData();
        // 创建表格准备工作(统计列数)
        int colCount = statisticalColCount(readyDatas);
        // 表格标题
        XWPFParagraph tableTile = document.createParagraph();
        tableTile.createRun().setText("毕业要求指标点与考核内容的对应关系如下表所示");
        tableTile.setAlignment(ParagraphAlignment.CENTER);
        // 表格部分
        XWPFTable table = document.createTable(tableHeader.size(), colCount);
        // 第0行(表格的表头)
        XWPFTableRow row = table.getRow(0);
    }


    /**
     * 统计表格需要的列数
     * @param tableContents 表格需要填充的内容够
     * @return 需要的列数
     */
    public static int statisticalColCount(List<TableContent> tableContents) {
        int colCount = 0;
        // 一级不为空
        if (CollectionUtils.isNotEmpty(tableContents)) {
            for (TableContent tableContent : tableContents) {
                // 获取二级
                List<TableContent> seconds = tableContent.getTableContents();
                // 二级不为空
                if (CollectionUtils.isNotEmpty(seconds)) {
                    for (TableContent second : seconds) {
                        // 获取三级
                        List<TableContent> trees = second.getTableContents();
                        // 三级不为空
                        if (CollectionUtils.isNotEmpty(trees)) {
                            colCount += trees.size();
                        } else {
                            colCount++;
                        }
                    }
                }
            }
        }
        return colCount;
    }



    /**
     * 表格所有的单元格内容居中
     *
     * @param table 表格
     */
    public static void cellContentCenter(XWPFTable table) {
        // 获取所有的行
        List<XWPFTableRow> rows = table.getRows();
        if (CollectionUtils.isNotEmpty(rows)) {
            // 遍历行，获取所有的单元格
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> tableCells = row.getTableCells();
                // 如果单元格集合不为空
                if (CollectionUtils.isNotEmpty(tableCells)) {
                    for (XWPFTableCell tableCell : tableCells) {
                        CTTc ctt1c = tableCell.getCTTc();
                        CTTcPr ctP1r = ctt1c.addNewTcPr();
                        ctP1r.addNewVAlign().setVal(STVerticalJc.CENTER);
                        for (CTP ctp : ctt1c.getPList()) {
                            ctp.addNewPPr().addNewJc().setVal(STJc.CENTER);
                        }
                    }
                }
            }
        }
    }


    /**
     * 准备数据毕业要求指标点
     * @return 集合
     */
    public static List<TableContent> readyData() {
        // 三级部分
        List<TableContent> threes = new ArrayList<>();
        List<TableContent> threes2 = new ArrayList<>();
        List<TableContent> threes3 = new ArrayList<>();
        List<TableContent> threes4 = new ArrayList<>();
        TableContent threeTableContent = new TableContent();
        TableContent threeTableContent2 = new TableContent();
        TableContent threeTableContent3 = new TableContent();
        TableContent threeTableContent4 = new TableContent();
        TableContent threeTableContent5 = new TableContent();
        TableContent threeTableContent6 = new TableContent();
        TableContent threeTableContent7 = new TableContent();
        TableContent threeTableContent8 = new TableContent();
        threeTableContent.setContent("平时成绩（30%）：\n作业一、作业二");
        threeTableContent2.setContent("期末考试（70%）：\n第一、二、三大题");
        threeTableContent3.setContent("平时成绩（30%）：\n作业一、作业二");
        threeTableContent4.setContent("期末考试（70%）：\n第一、二、三大题");
        threeTableContent5.setContent("平时成绩（30%）：\n作业一、作业二");
        threeTableContent6.setContent("期末考试（70%）：\n第一、二、三大题");
        threeTableContent7.setContent("平时成绩（30%）：\n作业一、作业二");
        threeTableContent8.setContent("期末考试（70%）：\n第一、二、三大题");
        threes.add(threeTableContent);
        threes.add(threeTableContent2);
        threes2.add(threeTableContent3);
        threes2.add(threeTableContent4);
        threes3.add(threeTableContent5);
        threes3.add(threeTableContent6);
        threes4.add(threeTableContent7);
        threes4.add(threeTableContent8);


        // 二级部分
        List<TableContent> seconds = new ArrayList<>();
        List<TableContent> seconds2 = new ArrayList<>();
        TableContent secondTableContent = new TableContent();
        TableContent secondTableContent2 = new TableContent();
        TableContent secondTableContent3 = new TableContent();
        TableContent secondTableContent4 = new TableContent();
        secondTableContent.setContent("课程目标1： 掌握数据库系统的基本概念、基本原理，了解数据库技术的最新发展动");
        secondTableContent2.setContent("课程目标 2：掌握关系数据库的基本概念、SQL语言编程和关系数据理论");
        secondTableContent3.setContent("课程目标 3：具备运行与维护数据库系统的技能");
        secondTableContent4.setContent("课程目标 4：掌握各种数据模型的特点、建模思想、规范化的设计理论和方法");
        secondTableContent.setTableContents(threes);
        secondTableContent2.setTableContents(threes2);
        secondTableContent3.setTableContents(threes3);
        secondTableContent4.setTableContents(threes4);
        seconds.add(secondTableContent);
        seconds.add(secondTableContent2);
        seconds2.add(secondTableContent3);
        seconds2.add(secondTableContent4);
        // 一级部分
        List<TableContent> first = new ArrayList<>();
        TableContent firstTableContent = new TableContent();
        TableContent firstTableContent2 = new TableContent();
        firstTableContent.setContent("1.2掌握解决复杂软件工程问题所必需的计算科学基础知识。");
        firstTableContent.setTableContents(seconds);
        firstTableContent2.setContent("2.2能够针对软件工程问题或软件系统建立合适的模型，清晰地表达和描述复杂软件工程问题。");
        firstTableContent2.setTableContents(seconds2);
        first.add(firstTableContent);
        first.add(firstTableContent2);
        return first;
    }




    /**
     *  查询wold中的数据 返回List 集合
     * @param path wold所在的地址
     * @return list
     */
    public List<String> query(String path){
        List<String> list  = new ArrayList<>();
        try{
            FileInputStream stream = new FileInputStream(path);
            // 创建Word文件
            XWPFDocument doc = new XWPFDocument(stream);
            //遍历段落
            for(XWPFParagraph p : doc.getParagraphs()) {
                System.out.println(p.getParagraphText());
                list.add(p.getParagraphText());
            }
        }catch (Exception e){
            e.printStackTrace();
        }
        return list;
    }


    /**
     * 为文档创建页码
     * @param document 文档
     */
    public static void createPageNum(XWPFDocument document) {
        XWPFFooter footer = document.createFooter(HeaderFooterType.DEFAULT);
        paragraph = footer.getParagraphArray(0);
        if (paragraph == null) {
            paragraph = footer.createParagraph();
        }
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        paragraph.getCTP().addNewFldSimple().setInstr("PAGE");
    }






//    /**
//     *
//     * @param headingLevel	标题级别（1）
//     * @param pointSize	字体大小（45）
//     * @param hexColor	字体颜色（"000000"）
//     * @param typefaceName	字体名称（默认宋体）
//     */
//    public static String createHeadingStyle5_0_0(XWPFDocument document, int headingLevel,
//                                                 int pointSize, String hexColor, String typefaceName) {
//        String customStyle = "Heading" + headingLevel;
//        XWPFStyles styles = document.createStyles();
//        // 创建样式
//        CTStyle ctStyle = CTStyle.Factory.newInstance();
//        // 设置id
//        ctStyle.setStyleId(customStyle);
//
//        CTString styleName = CTString.Factory.newInstance();
//        styleName.setVal(customStyle);
//        ctStyle.setName(styleName);
//
//        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
//        indentNumber.setVal(BigInteger.valueOf(headingLevel));
//
//        // 数字越低在格式栏中越突出
//        ctStyle.setUiPriority(indentNumber);
//
//        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
//        ctStyle.setUnhideWhenUsed(onoffnull);
//
//        // 样式将显示在“格式”栏中
//        ctStyle.setQFormat(onoffnull);
//
//        // 样式定义给定级别的标题
//        CTPPrGeneral ppr = CTPPrGeneral.Factory.newInstance();
//        ppr.setOutlineLvl(indentNumber);
//        ctStyle.setPPr(ppr);
//
//        XWPFStyle style = new XWPFStyle(ctStyle);
//
//        CTHpsMeasure size = CTHpsMeasure.Factory.newInstance();
//        size.setVal(new BigInteger(String.valueOf(pointSize)));
//        CTHpsMeasure size2 = CTHpsMeasure.Factory.newInstance();
//        size2.setVal(new BigInteger(String.valueOf(pointSize)));
//
//        CTFonts fonts = CTFonts.Factory.newInstance();
//        if (typefaceName == null || "".equals(typefaceName)) {
//            typefaceName = "宋体";
//        }
//        // 字体
//        fonts.setAscii(typefaceName);
//
//        CTRPr rpr = CTRPr.Factory.newInstance();
//        rpr.setRFontsArray(new CTFonts[]{fonts});
//        rpr.setSzArray(new CTHpsMeasure[]{size});
//        // 字体大小
//        rpr.setSzCsArray(new CTHpsMeasure[]{size2});
//
//        CTColor color=CTColor.Factory.newInstance();
//        color.setVal(hexToBytes(hexColor));
//        //字体颜色
//        rpr.setColorArray(new CTColor[]{color});
//        style.getCTStyle().setRPr(rpr);
//        style.setType(STStyleType.PARAGRAPH);
////        styles.addStyle(style);
//        return customStyle;
//    }




    /**
     *
     * @param headingLevel	标题级别（1）
     * @param pointSize	字体大小（45）
     * @param hexColor	字体颜色（"000000"）
     * @param typefaceName	字体名称（默认宋体）
     */
//    public static String createHeadingStyle4_1_2(XWPFDocument document, int headingLevel,
//                                            int pointSize, String hexColor, String typefaceName) {
//        String customStyle = "Heading" + headingLevel;
//        XWPFStyles styles = document.createStyles();
//        // 创建样式
//        CTStyle ctStyle = CTStyle.Factory.newInstance();
//        // 设置id
//        ctStyle.setStyleId(customStyle);
//
//        CTString styleName = CTString.Factory.newInstance();
//        styleName.setVal(customStyle);
//        ctStyle.setName(styleName);
//
//        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
//        indentNumber.setVal(BigInteger.valueOf(headingLevel));
//
//        // 数字越低在格式栏中越突出
//        ctStyle.setUiPriority(indentNumber);
//
//        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
//        ctStyle.setUnhideWhenUsed(onoffnull);
//
//        // 样式将显示在“格式”栏中
//        ctStyle.setQFormat(onoffnull);
//
//        // 样式定义给定级别的标题
//        CTPPr ppr = CTPPr.Factory.newInstance();
//        ppr.setOutlineLvl(indentNumber);
//        ctStyle.setPPr(ppr);
//
//        XWPFStyle style = new XWPFStyle(ctStyle);
//
//        CTHpsMeasure size = CTHpsMeasure.Factory.newInstance();
//        size.setVal(new BigInteger(String.valueOf(pointSize)));
//        CTHpsMeasure size2 = CTHpsMeasure.Factory.newInstance();
//        size2.setVal(new BigInteger(String.valueOf(pointSize)));
//
//        CTFonts fonts = CTFonts.Factory.newInstance();
//        if (typefaceName == null || "".equals(typefaceName)) {
//            typefaceName = "宋体";
//        }
//        // 字体
//        fonts.setAscii(typefaceName);
//
//        CTRPr rpr = CTRPr.Factory.newInstance();
//        rpr.setRFonts(fonts);
//        rpr.setSz(size);
//        // 字体大小
//        rpr.setSzCs(size2);
//
//        CTColor color=CTColor.Factory.newInstance();
//        color.setVal(hexToBytes(hexColor));
//        //字体颜色
//        rpr.setColor(color);
//        style.getCTStyle().setRPr(rpr);
//        style.setType(STStyleType.PARAGRAPH);
//        styles.addStyle(style);
//        return customStyle;
//    }



    public static byte[] hexToBytes(String hexString) {
        HexBinaryAdapter adapter = new HexBinaryAdapter();
        return adapter.unmarshal(hexString);
    }





    /**
     * 创建带有书签的标题
     */
    public static void createTitleWithBookmark(XWPFDocument doc, String title, String paragraphStyleId) {
        // 获取所有的段落列表
        List<XWPFParagraph> paragraphs = doc.getParagraphs();
        // 创建段落
        XWPFParagraph paragraph = doc.createParagraph();
        // 创建书签
        CTBookmark ctBookmark = paragraph.getCTP().addNewBookmarkStart();
        // 设置书签开始位置名称
        ctBookmark.setName("_Toc" + UUID.randomUUID());
        // 设置书签开始位置id
        BigInteger currentId = BigInteger.valueOf(paragraphs.size() + 1);
        ctBookmark.setId(currentId);
        // 设置标题内容
        XWPFRun run = paragraph.createRun();
        run.setText(title);
        run.addBreak();
        // 设置标题样式id
        paragraph.setStyle(paragraphStyleId);
        // 创建段落书签结束位置
        CTMarkupRange ctMarkupRange = paragraph.getCTP().addNewBookmarkEnd();
        ctMarkupRange.setId(currentId);
    }



    /**
     *
     * @param headingLevel	标题级别（1）
     * @param pointSize	字体大小（45）
     * @param hexColor	字体颜色（"000000"）
     * @param typefaceName	字体名称（默认宋体）
     */
    public static String createHeadingStyle5_0_0(XWPFDocument document, int headingLevel,
                                            int pointSize, String hexColor, String typefaceName) {
        String customStyle = "Heading" + headingLevel;
        XWPFStyles styles = document.createStyles();
        // 创建样式
        CTStyle ctStyle = CTStyle.Factory.newInstance();
        // 设置id
        ctStyle.setStyleId(customStyle);

        CTString styleName = CTString.Factory.newInstance();
        styleName.setVal(customStyle);
        ctStyle.setName(styleName);

        CTDecimalNumber indentNumber = CTDecimalNumber.Factory.newInstance();
        indentNumber.setVal(BigInteger.valueOf(headingLevel));

        // 数字越低在格式栏中越突出
        ctStyle.setUiPriority(indentNumber);

        CTOnOff onoffnull = CTOnOff.Factory.newInstance();
        ctStyle.setUnhideWhenUsed(onoffnull);

        // 样式将显示在“格式”栏中
        ctStyle.setQFormat(onoffnull);

        // 样式定义给定级别的标题
        CTPPrGeneral ppr = CTPPrGeneral.Factory.newInstance();
        ppr.setOutlineLvl(indentNumber);
        ctStyle.setPPr(ppr);

        XWPFStyle style = new XWPFStyle(ctStyle);

        CTHpsMeasure size = CTHpsMeasure.Factory.newInstance();
        size.setVal(new BigInteger(String.valueOf(pointSize)));
        CTHpsMeasure size2 = CTHpsMeasure.Factory.newInstance();
        size2.setVal(new BigInteger(String.valueOf(pointSize)));

        CTFonts fonts = CTFonts.Factory.newInstance();
        if (typefaceName == null || "".equals(typefaceName)) {
            typefaceName = "宋体";
        }
        // 字体
        fonts.setAscii(typefaceName);

        CTRPr rpr = CTRPr.Factory.newInstance();
        rpr.setRFontsArray(new CTFonts[]{fonts});
        rpr.setSzArray(new CTHpsMeasure[]{size});
        // 字体大小
        rpr.setSzCsArray(new CTHpsMeasure[]{size2});

        CTColor color=CTColor.Factory.newInstance();
        color.setVal(hexToBytes(hexColor));
        //字体颜色
        rpr.setColorArray(new CTColor[]{color});
        style.getCTStyle().setRPr(rpr);
        style.setType(STStyleType.PARAGRAPH);
        styles.addStyle(style);
        return customStyle;
    }




    /**
     * 创建文档标题
     *
     * @param document 文档对象
     * @param text     标题内容
     * @param fontFamily 字体
     * @param fontSize  字体大小
     */
    public static void createDocumentTitle(XWPFDocument document, String text,String fontFamily, int fontSize) {
        //添加标题
        XWPFParagraph titleParagraph = document.createParagraph();
        //设置段落居中
        titleParagraph.setAlignment(ParagraphAlignment.CENTER);

        XWPFRun titleParagraphRun = titleParagraph.createRun();
        titleParagraphRun.setText(text);
        if (StringUtils.isBlank(fontFamily)) {
            fontFamily = "宋体";
        }
        titleParagraphRun.setFontFamily(fontFamily);
        titleParagraphRun.setFontSize(fontSize);
        titleParagraphRun.setBold(true);
    }


    /**
     * 创建二级标题
     *
     * @param document 文档对象
     * @param text     标题内容
     */
    public static void createSecondTitle(XWPFDocument document, String text) {
        XWPFParagraph paragraph = document.createParagraph();
        paragraph.setAlignment(ParagraphAlignment.LEFT);
        XWPFRun xwpfRun = paragraph.createRun();
        xwpfRun.setText(text);
        xwpfRun.setText("\r");
        xwpfRun.setFontFamily("宋体");
//        xwpfRun.setFontSize(10);
        xwpfRun.setBold(true);
    }



    /**
     * 创建空行
     *
     * @param document 文档对象
     * @param counts   空行个数
     */
    public static void createEmptyLine(XWPFDocument document, int counts) {
        for (int i = 0; i < counts; i++) {
            XWPFParagraph empty = document.createParagraph();
            XWPFRun e = empty.createRun();
            e.setText("");
        }
    }



    /**
     * 给表格字体内容宋体、居中、首行加粗
     *
     * @param comTable 表格对象
     */
    public static void tableContentSongTiCenterFirstFontBold(XWPFTable comTable) {
        List<XWPFTableRow> rows = comTable.getRows();
        if (CollectionUtils.isNotEmpty(rows)) {
            // 对所有单元格处理：宋体、内容居中
            for (int i = 0; i < rows.size(); i++) {
                List<XWPFTableCell> tableCells = rows.get(i).getTableCells();
                if (CollectionUtils.isNotEmpty(tableCells)) {
                    for (XWPFTableCell tableCell : tableCells) {
                        CTTc ctTc = tableCell.getCTTc();
                        CTP ctp = ctTc.getPList().get(0);
                        CTPPr ctpPr = ctp.addNewPPr();
                        CTParaRPr ctParaRPr = ctpPr.addNewRPr();
                        List<CTR> rList = ctp.getRList();
                        if (CollectionUtils.isNotEmpty(rList)) {
                            for (CTR ctr : rList) {
                                CTRPr ctrPr = ctr.addNewRPr();
                                // 如果是首行，加粗处理
                                if (i == 0) {
                                    // 以下是加粗处理
                                    ctParaRPr.addNewB();
                                    ctParaRPr.addNewBCs();
                                    ctrPr.addNewB();
                                    ctrPr.addNewBCs();
                                }
                                // 以下为宋体设置
                                CTFonts ctFonts1 = ctrPr.addNewRFonts();
                                ctFonts1.setHAnsi("宋体");
                                ctFonts1.setAscii("宋体");
                                ctFonts1.setEastAsia("宋体");
                            }
                        }
                        // 居中
                        CTTcPr ctP1r = ctTc.addNewTcPr();
                        ctP1r.addNewVAlign().setVal(STVerticalJc.CENTER);
                        ctpPr.addNewJc().setVal(STJc.CENTER);
                        // 设置宋体
                        CTFonts ctFonts = ctParaRPr.addNewRFonts();
                        ctFonts.setHAnsi("宋体");
                        ctFonts.setAscii("宋体");
                        ctFonts.setEastAsia("宋体");
                    }
                }
            }
        }
    }



    /**
     * 给表格字体内容宋体、居中
     *
     * @param comTable 表格对象
     */
    public static void tableSongTiCenter(XWPFTable comTable) {
        List<XWPFTableRow> rows = comTable.getRows();
        if (CollectionUtils.isNotEmpty(rows)) {
            // 对所有单元格处理：宋体、内容居中
            for (XWPFTableRow row : rows) {
                List<XWPFTableCell> tableCells = row.getTableCells();
                if (CollectionUtils.isNotEmpty(tableCells)) {
                    for (XWPFTableCell tableCell : tableCells) {
                        CTTc ctTc = tableCell.getCTTc();
                        CTP ctp = ctTc.getPList().get(0);
                        CTPPr ctpPr = ctp.addNewPPr();
                        CTParaRPr ctParaRPr = ctpPr.addNewRPr();
                        List<CTR> rList = ctp.getRList();
                        if (CollectionUtils.isNotEmpty(rList)) {
                            for (CTR ctr : rList) {
                                CTRPr ctrPr = ctr.addNewRPr();
                                // 以下为宋体设置
                                CTFonts ctFonts1 = ctrPr.addNewRFonts();
                                ctFonts1.setHAnsi("宋体");
                                ctFonts1.setAscii("宋体");
                                ctFonts1.setEastAsia("宋体");
                            }
                        }
                        // 居中
                        CTTcPr ctP1r = ctTc.addNewTcPr();
                        ctP1r.addNewVAlign().setVal(STVerticalJc.CENTER);
                        ctpPr.addNewJc().setVal(STJc.CENTER);
                        // 设置宋体
                        CTFonts ctFonts = ctParaRPr.addNewRFonts();
                        ctFonts.setHAnsi("宋体");
                        ctFonts.setAscii("宋体");
                        ctFonts.setEastAsia("宋体");
                    }
                }
            }
        }
    }



    /**
     * 输出文档
     *
     * @param request  http请求
     * @param response http响应
     * @param document 文档对象
     * @param fileName 文件名称
     */
    public static void drawReportExport(HttpServletRequest request, HttpServletResponse response, XWPFDocument document, String fileName) throws Exception {
        //根据浏览器内核判断前端浏览器类型，避免IE内核浏览器导出文件名乱码
        String agent = request.getHeader("User-Agent");
        boolean isMsie = ((agent != null && agent.contains("MSIE")) || (null != agent && agent.contains("like Gecko")));
        if (isMsie) {
            //IE浏览器内核
            fileName = new String(fileName.getBytes("GBK"), StandardCharsets.ISO_8859_1);
        } else {
            //chrome浏览器内核
            fileName = new String(fileName.getBytes(StandardCharsets.UTF_8), StandardCharsets.ISO_8859_1);
        }
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/octet-stream;charset=utf-8");
        response.addHeader("Content-Disposition", "attachment;filename=" + fileName + ".docx");
        document.write(response.getOutputStream());
        response.getOutputStream().flush();
        response.getOutputStream().close();
    }



    /**
     * 单元格左对齐
     * @param tableCell 单元格
     */
    public static void setTableCellLeft(XWPFTableCell tableCell) {
        CTTc ctTc = tableCell.getCTTc();
        // 居中
        CTTcPr ctP1r = ctTc.addNewTcPr();
        ctP1r.addNewVAlign().setVal(STVerticalJc.CENTER);
        CTP ctp = ctTc.getPList().get(0);
        CTPPr ctpPr = ctp.addNewPPr();
        ctpPr.addNewJc().setVal(STJc.LEFT);
    }


    /**
     * 单元格文字加粗处理
     * @param tableCell 单元格
     */
    public static void setTableCellBold(XWPFTableCell tableCell) {
        CTTc ctTc = tableCell.getCTTc();
        CTP ctp = ctTc.getPList().get(0);
        CTPPr ctpPr = ctp.addNewPPr();
        CTParaRPr ctParaRPr = ctpPr.addNewRPr();
        List<CTR> rList = ctp.getRList();
        if (CollectionUtils.isNotEmpty(rList)) {
            for (CTR ctr : rList) {
                CTRPr ctrPr = ctr.addNewRPr();
                // 以下是加粗处理
                ctParaRPr.addNewB();
                ctParaRPr.addNewBCs();
                ctrPr.addNewB();
                ctrPr.addNewBCs();
            }
        }
    }




    /**
     * 文本输出并居中显示
     */
    public static void writeLineCenter(XWPFDocument document, String text) {
        XWPFParagraph paragraph = document.createParagraph();
        paragraph.setAlignment(ParagraphAlignment.CENTER);
        XWPFRun xwpfRun = paragraph.createRun();
        xwpfRun.setText(text);
        xwpfRun.setFontFamily("宋体");
    }


    /**
     * 设置单元格字体颜色
     *
     * @param cell 单元格
     * @param rgbColor rgb颜色字符串，如：FF0000，红色
     */
    public static void setCellTextColor(XWPFTableCell cell, String rgbColor) {
        List<CTP> pList = cell.getCTTc().getPList();
        if (CollectionUtils.isNotEmpty(pList)) {
            CTP p = pList.get(0);
            CTPPr ppr = p.addNewPPr();
            CTParaRPr rPr = ppr.addNewRPr();
            rPr.addNewColor().setVal(rgbColor);

            List<CTR> rList = p.getRList();
            if (CollectionUtils.isNotEmpty(rList)) {
                CTR r = rList.get(0);
                CTRPr rPr1 = r.addNewRPr();
                rPr1.addNewColor().setVal(rgbColor);
            }
        }

    }



    /**
     * 固定宽度,均分表格的每个列
     *
     * @param table 表格
     * @param width 单元格宽度
     */
    public static void setTableWidth(XWPFTable table, String width) {
        //列宽自动分割
        CTTblWidth table1Width = table.getCTTbl().addNewTblPr().addNewTblW();
        table1Width.setType(STTblWidth.DXA);
        table1Width.setW(BigInteger.valueOf(8200));

        CTTblLayoutType layoutType = table.getCTTbl().getTblPr().addNewTblLayout();
        layoutType.setType(STTblLayoutType.FIXED);

        for (XWPFTableRow row : table.getRows()) {
            List<XWPFTableCell> tableCells = row.getTableCells();
            for (XWPFTableCell cell : tableCells) {
                cell.setWidth(width);
            }
        }
    }

    /**
     * 固定宽度,均分表格的每个列
     *
     * @param table 表格
     * @param widthList 单元格宽度
     */
    public static void setTableWidth(XWPFTable table, List<String> widthList) {
        //列宽自动分割
        CTTblWidth table1Width = table.getCTTbl().addNewTblPr().addNewTblW();
        table1Width.setType(STTblWidth.DXA);
        table1Width.setW(BigInteger.valueOf(8200));

        CTTblLayoutType layoutType = table.getCTTbl().getTblPr().addNewTblLayout();
        layoutType.setType(STTblLayoutType.FIXED);

        for (XWPFTableRow row : table.getRows()) {
            List<XWPFTableCell> tableCells = row.getTableCells();
            for (int i = 0; i <tableCells.size() ; i++) {
                tableCells.get(i).setWidth(widthList.get(i));
            }
        }
    }




    /**
     * word单元格列合并(原生)
     *
     * @param table     表格
     * @param row       合并列所在行
     * @param startCell 开始列
     * @param endCell   结束列
     * @since 2020年4月8日 下午4:43:54
     */
    public static void mergeCellsHorizontal(XWPFTable table, int row, int startCell, int endCell) {
        for (int i = startCell; i <= endCell; i++) {
            XWPFTableCell cell = table.getRow(row).getCell(i);
            if (i == startCell) {
                if (cell != null) {
                    // The first merged cell is set with RESTART merge value
                    cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.RESTART);
                }

            } else {
                if (cell != null) {
                    // Cells which join (merge) the first one, are set with CONTINUE
                    cell.getCTTc().addNewTcPr().addNewHMerge().setVal(STMerge.CONTINUE);
                }

            }
        }
    }

    /**
     * word单元格行合并(原生)
     *
     * @param table    表格
     * @param col      合并行所在列
     * @param startRow 开始行
     * @param endRow   结束行
     * @since 2020年4月8日 下午4:46:18
     */
    public static void mergeCellsVertically(XWPFTable table, int col, int startRow, int endRow) {
        for (int i = startRow; i <= endRow; i++) {
            XWPFTableCell cell = table.getRow(i).getCell(col);
            if (i == startRow) {
                // The first merged cell is set with RESTART merge value
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.RESTART);
            } else {
                // Cells which join (merge) the first one, are set with CONTINUE
                cell.getCTTc().addNewTcPr().addNewVMerge().setVal(STMerge.CONTINUE);
            }
        }
    }




    /**
     * 创建饼状图
     * <p>
     * 注意：xAxis和values数组的长度要一致，values中的元素可以为null
     *
     * @param document   文档
     * @param chartTitle 饼状图标题
     * @param xAxis      饼状图图例说明
     * @param values     饼状图数据
     */
    public static void createPieChart(XWPFDocument document, String chartTitle, String[] xAxis, Double[] values) throws Exception {
        // 柱状图数据
        if (xAxis.length == 0 || values.length == 0) {
            return;
        }
        // 创建图表
        XWPFChart chart = document.createChart(14 * Units.EMU_PER_CENTIMETER, 9 * Units.EMU_PER_CENTIMETER);
        chart.setTitleText(chartTitle);
        // 标题不覆盖图表
        chart.setTitleOverlay(false);

        // 图例的位置
        XDDFChartLegend legend = chart.getOrAddLegend();
        legend.setPosition(LegendPosition.BOTTOM);

        // x轴数据
        XDDFCategoryDataSource categoriesData = XDDFDataSourcesFactory.fromArray(xAxis);
        // y轴数据
        XDDFNumericalDataSource<Double> valuesDataA = XDDFDataSourcesFactory.fromArray(values);

        XDDFPieChartData chartData = (XDDFPieChartData) chart.createData(ChartTypes.PIE, null, null);
        chartData.setVaryColors(true);

        // 填充数据
        chartData.addSeries(categoriesData, valuesDataA);

        // 饼图上显示具体数值
        CTDLbls ctdLbls = chart.getCTChart().getPlotArea().getPieChartArray(0).addNewDLbls();
        ctdLbls.addNewShowLegendKey().setVal(false);
        ctdLbls.addNewShowVal().setVal(true);
        ctdLbls.addNewShowPercent().setVal(false);
        ctdLbls.addNewShowCatName().setVal(false);
        ctdLbls.addNewShowSerName().setVal(false);
        ctdLbls.addNewLeaderLines();
        // 图表边框颜色设置为灰色
        chart.getCTChartSpace().addNewSpPr().addNewLn().addNewSolidFill().addNewSchemeClr().setVal(STSchemeColorVal.BG_2);
        // 边框直角
        chart.getCTChartSpace().addNewRoundedCorners().setVal(false);
        // 如果图表中有占比为null的选项，则忽略不显示
        chart.getCTChart().addNewDispBlanksAs().setVal(STDispBlanksAs.GAP);
        // 绘画图表
        chart.plot(chartData);
    }
}